/*
 *  lgl-barcode-onecode.c
 *  Copyright (C) 2010  Jim Evins <evins@snaught.com>.
 *
 *  This file is part of libglbarcode.
 *
 *  libglbarcode is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  libglbarcode is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with libglbarcode.  If not, see <http://www.gnu.org/licenses/>.
 */

/*
 * This module implements the Intelligent Mail (OneCode) barcode
 * specified in the USPS specification USPS-B-3200E, 07/08/05.
 */

#include <config.h>

#include "lgl-barcode-onecode.h"

#include <glib.h>
#include <ctype.h>
#include <string.h>

/*========================================================*/
/* Private macros and constants.                          */
/*========================================================*/

#define CHAR_A 0
#define CHAR_B 1
#define CHAR_C 2
#define CHAR_D 3
#define CHAR_E 4
#define CHAR_F 5
#define CHAR_G 6
#define CHAR_H 7
#define CHAR_I 8
#define CHAR_J 9

#define PTS_PER_INCH 72.0

#define ONECODE_BAR_WIDTH        ( 0.02   * PTS_PER_INCH )
#define ONECODE_FULL_HEIGHT      ( 0.145  * PTS_PER_INCH )
#define ONECODE_ASCENDER_HEIGHT  ( 0.0965 * PTS_PER_INCH )
#define ONECODE_DESCENDER_HEIGHT ( 0.0965 * PTS_PER_INCH )
#define ONECODE_TRACKER_HEIGHT   ( 0.048  * PTS_PER_INCH )
#define ONECODE_FULL_OFFSET      0
#define ONECODE_ASCENDER_OFFSET  0
#define ONECODE_DESCENDER_OFFSET ( 0.0485 * PTS_PER_INCH )
#define ONECODE_TRACKER_OFFSET   ( 0.0485 * PTS_PER_INCH )
#define ONECODE_BAR_PITCH        ( 0.0458 * PTS_PER_INCH )
#define ONECODE_HORIZ_MARGIN     ( 0.125  * PTS_PER_INCH )
#define ONECODE_VERT_MARGIN      ( 0.028  * PTS_PER_INCH )


/*========================================================*/
/* Private types.                                         */
/*========================================================*/

typedef struct {
        guchar byte[13];
} Int104;

typedef struct {
        struct { gint i; gint mask; } descender;
        struct { gint i; gint mask; } ascender;
} BarMapEntry;


/*===========================================*/
/* Private globals                           */
/*===========================================*/

static BarMapEntry bar_map[] = {
        /*  1 */ { { CHAR_H, 1<<2  }, { CHAR_E, 1<<3  } },
        /*  2 */ { { CHAR_B, 1<<10 }, { CHAR_A, 1<<0  } },
        /*  3 */ { { CHAR_J, 1<<12 }, { CHAR_C, 1<<8  } },
        /*  4 */ { { CHAR_F, 1<<5  }, { CHAR_G, 1<<11 } },
        /*  5 */ { { CHAR_I, 1<<9  }, { CHAR_D, 1<<1  } },
        /*  6 */ { { CHAR_A, 1<<1  }, { CHAR_F, 1<<12 } },
        /*  7 */ { { CHAR_C, 1<<5  }, { CHAR_B, 1<<8  } },
        /*  8 */ { { CHAR_E, 1<<4  }, { CHAR_J, 1<<11 } },
        /*  9 */ { { CHAR_G, 1<<3  }, { CHAR_I, 1<<10 } },
        /* 10 */ { { CHAR_D, 1<<9  }, { CHAR_H, 1<<6  } },
        /* 11 */ { { CHAR_F, 1<<11 }, { CHAR_B, 1<<4  } },
        /* 12 */ { { CHAR_I, 1<<5  }, { CHAR_C, 1<<12 } },
        /* 13 */ { { CHAR_J, 1<<10 }, { CHAR_A, 1<<2  } },
        /* 14 */ { { CHAR_H, 1<<1  }, { CHAR_G, 1<<7  } },
        /* 15 */ { { CHAR_D, 1<<6  }, { CHAR_E, 1<<9  } },
        /* 16 */ { { CHAR_A, 1<<3  }, { CHAR_I, 1<<6  } },
        /* 17 */ { { CHAR_G, 1<<4  }, { CHAR_C, 1<<7  } },
        /* 18 */ { { CHAR_B, 1<<1  }, { CHAR_J, 1<<9  } },
        /* 19 */ { { CHAR_H, 1<<10 }, { CHAR_F, 1<<2  } },
        /* 20 */ { { CHAR_E, 1<<0  }, { CHAR_D, 1<<8  } },
        /* 21 */ { { CHAR_G, 1<<2  }, { CHAR_A, 1<<4  } },
        /* 22 */ { { CHAR_I, 1<<11 }, { CHAR_B, 1<<0  } },
        /* 23 */ { { CHAR_J, 1<<8  }, { CHAR_D, 1<<12 } },
        /* 24 */ { { CHAR_C, 1<<6  }, { CHAR_H, 1<<7  } },
        /* 25 */ { { CHAR_F, 1<<1  }, { CHAR_E, 1<<10 } },
        /* 26 */ { { CHAR_B, 1<<12 }, { CHAR_G, 1<<9  } },
        /* 27 */ { { CHAR_H, 1<<3  }, { CHAR_I, 1<<0  } },
        /* 28 */ { { CHAR_F, 1<<8  }, { CHAR_J, 1<<7  } },
        /* 29 */ { { CHAR_E, 1<<6  }, { CHAR_C, 1<<10 } },
        /* 30 */ { { CHAR_D, 1<<4  }, { CHAR_A, 1<<5  } },
        /* 31 */ { { CHAR_I, 1<<4  }, { CHAR_F, 1<<7  } },
        /* 32 */ { { CHAR_H, 1<<11 }, { CHAR_B, 1<<9  } },
        /* 33 */ { { CHAR_G, 1<<0  }, { CHAR_J, 1<<6  } },
        /* 34 */ { { CHAR_A, 1<<6  }, { CHAR_E, 1<<8  } },
        /* 35 */ { { CHAR_C, 1<<1  }, { CHAR_D, 1<<2  } },
        /* 36 */ { { CHAR_F, 1<<9  }, { CHAR_I, 1<<12 } },
        /* 37 */ { { CHAR_E, 1<<11 }, { CHAR_G, 1<<1  } },
        /* 38 */ { { CHAR_J, 1<<5  }, { CHAR_H, 1<<4  } },
        /* 39 */ { { CHAR_D, 1<<3  }, { CHAR_B, 1<<2  } },
        /* 40 */ { { CHAR_A, 1<<7  }, { CHAR_C, 1<<0  } },
        /* 41 */ { { CHAR_B, 1<<3  }, { CHAR_E, 1<<1  } },
        /* 42 */ { { CHAR_G, 1<<10 }, { CHAR_D, 1<<5  } },
        /* 43 */ { { CHAR_I, 1<<7  }, { CHAR_J, 1<<4  } },
        /* 44 */ { { CHAR_C, 1<<11 }, { CHAR_F, 1<<6  } },
        /* 45 */ { { CHAR_A, 1<<8  }, { CHAR_H, 1<<12 } },
        /* 46 */ { { CHAR_E, 1<<2  }, { CHAR_I, 1<<1  } },
        /* 47 */ { { CHAR_F, 1<<10 }, { CHAR_D, 1<<0  } },
        /* 48 */ { { CHAR_J, 1<<3  }, { CHAR_A, 1<<9  } },
        /* 49 */ { { CHAR_G, 1<<5  }, { CHAR_C, 1<<4  } },
        /* 50 */ { { CHAR_H, 1<<8  }, { CHAR_B, 1<<7  } },
        /* 51 */ { { CHAR_F, 1<<0  }, { CHAR_E, 1<<5  } },
        /* 52 */ { { CHAR_C, 1<<3  }, { CHAR_A, 1<<10 } },
        /* 53 */ { { CHAR_G, 1<<12 }, { CHAR_J, 1<<2  } },
        /* 54 */ { { CHAR_D, 1<<11 }, { CHAR_B, 1<<6  } },
        /* 55 */ { { CHAR_I, 1<<8  }, { CHAR_H, 1<<9  } },
        /* 56 */ { { CHAR_F, 1<<4  }, { CHAR_A, 1<<11 } },
        /* 57 */ { { CHAR_B, 1<<5  }, { CHAR_C, 1<<2  } },
        /* 58 */ { { CHAR_J, 1<<1  }, { CHAR_E, 1<<12 } },
        /* 59 */ { { CHAR_I, 1<<3  }, { CHAR_G, 1<<6  } },
        /* 60 */ { { CHAR_H, 1<<0  }, { CHAR_D, 1<<7  } },
        /* 61 */ { { CHAR_E, 1<<7  }, { CHAR_H, 1<<5  } },
        /* 62 */ { { CHAR_A, 1<<12 }, { CHAR_B, 1<<11 } },
        /* 63 */ { { CHAR_C, 1<<9  }, { CHAR_J, 1<<0  } },
        /* 64 */ { { CHAR_G, 1<<8  }, { CHAR_F, 1<<3  } },
        /* 65 */ { { CHAR_D, 1<<10 }, { CHAR_I, 1<<2  } }
};

static gchar * tdaf_table[4] = { "T", "D", "A", "F" };

static guint character_table[] = {
        /* Table I 5 of 13. */
          31, 7936,   47, 7808,   55, 7552,   59, 7040,   61, 6016,
          62, 3968,   79, 7744,   87, 7488,   91, 6976,   93, 5952,
          94, 3904,  103, 7360,  107, 6848,  109, 5824,  110, 3776,
         115, 6592,  117, 5568,  118, 3520,  121, 5056,  122, 3008,
         124, 1984,  143, 7712,  151, 7456,  155, 6944,  157, 5920,
         158, 3872,  167, 7328,  171, 6816,  173, 5792,  174, 3744,
         179, 6560,  181, 5536,  182, 3488,  185, 5024,  186, 2976,
         188, 1952,  199, 7264,  203, 6752,  205, 5728,  206, 3680,
         211, 6496,  213, 5472,  214, 3424,  217, 4960,  218, 2912,
         220, 1888,  227, 6368,  229, 5344,  230, 3296,  233, 4832,
         234, 2784,  236, 1760,  241, 4576,  242, 2528,  244, 1504,
         248,  992,  271, 7696,  279, 7440,  283, 6928,  285, 5904,
         286, 3856,  295, 7312,  299, 6800,  301, 5776,  302, 3728,
         307, 6544,  309, 5520,  310, 3472,  313, 5008,  314, 2960,
         316, 1936,  327, 7248,  331, 6736,  333, 5712,  334, 3664,
         339, 6480,  341, 5456,  342, 3408,  345, 4944,  346, 2896,
         348, 1872,  355, 6352,  357, 5328,  358, 3280,  361, 4816,
         362, 2768,  364, 1744,  369, 4560,  370, 2512,  372, 1488,
         376,  976,  391, 7216,  395, 6704,  397, 5680,  398, 3632,
         403, 6448,  405, 5424,  406, 3376,  409, 4912,  410, 2864,
         412, 1840,  419, 6320,  421, 5296,  422, 3248,  425, 4784,
         426, 2736,  428, 1712,  433, 4528,  434, 2480,  436, 1456,
         440,  944,  451, 6256,  453, 5232,  454, 3184,  457, 4720,
         458, 2672,  460, 1648,  465, 4464,  466, 2416,  468, 1392,
         472,  880,  481, 4336,  482, 2288,  484, 1264,  488,  752,
         527, 7688,  535, 7432,  539, 6920,  541, 5896,  542, 3848,
         551, 7304,  555, 6792,  557, 5768,  558, 3720,  563, 6536,
         565, 5512,  566, 3464,  569, 5000,  570, 2952,  572, 1928,
         583, 7240,  587, 6728,  589, 5704,  590, 3656,  595, 6472,
         597, 5448,  598, 3400,  601, 4936,  602, 2888,  604, 1864,
         611, 6344,  613, 5320,  614, 3272,  617, 4808,  618, 2760,
         620, 1736,  625, 4552,  626, 2504,  628, 1480,  632,  968,
         647, 7208,  651, 6696,  653, 5672,  654, 3624,  659, 6440,
         661, 5416,  662, 3368,  665, 4904,  666, 2856,  668, 1832,
         675, 6312,  677, 5288,  678, 3240,  681, 4776,  682, 2728,
         684, 1704,  689, 4520,  690, 2472,  692, 1448,  696,  936,
         707, 6248,  709, 5224,  710, 3176,  713, 4712,  714, 2664,
         716, 1640,  721, 4456,  722, 2408,  724, 1384,  728,  872,
         737, 4328,  738, 2280,  740, 1256,  775, 7192,  779, 6680,
         781, 5656,  782, 3608,  787, 6424,  789, 5400,  790, 3352,
         793, 4888,  794, 2840,  796, 1816,  803, 6296,  805, 5272,
         806, 3224,  809, 4760,  810, 2712,  812, 1688,  817, 4504,
         818, 2456,  820, 1432,  824,  920,  835, 6232,  837, 5208,
         838, 3160,  841, 4696,  842, 2648,  844, 1624,  849, 4440,
         850, 2392,  852, 1368,  865, 4312,  866, 2264,  868, 1240,
         899, 6200,  901, 5176,  902, 3128,  905, 4664,  906, 2616,
         908, 1592,  913, 4408,  914, 2360,  916, 1336,  929, 4280,
         930, 2232,  932, 1208,  961, 4216,  962, 2168,  964, 1144,
        1039, 7684, 1047, 7428, 1051, 6916, 1053, 5892, 1054, 3844,
        1063, 7300, 1067, 6788, 1069, 5764, 1070, 3716, 1075, 6532,
        1077, 5508, 1078, 3460, 1081, 4996, 1082, 2948, 1084, 1924,
        1095, 7236, 1099, 6724, 1101, 5700, 1102, 3652, 1107, 6468,
        1109, 5444, 1110, 3396, 1113, 4932, 1114, 2884, 1116, 1860,
        1123, 6340, 1125, 5316, 1126, 3268, 1129, 4804, 1130, 2756,
        1132, 1732, 1137, 4548, 1138, 2500, 1140, 1476, 1159, 7204,
        1163, 6692, 1165, 5668, 1166, 3620, 1171, 6436, 1173, 5412,
        1174, 3364, 1177, 4900, 1178, 2852, 1180, 1828, 1187, 6308,
        1189, 5284, 1190, 3236, 1193, 4772, 1194, 2724, 1196, 1700,
        1201, 4516, 1202, 2468, 1204, 1444, 1219, 6244, 1221, 5220,
        1222, 3172, 1225, 4708, 1226, 2660, 1228, 1636, 1233, 4452,
        1234, 2404, 1236, 1380, 1249, 4324, 1250, 2276, 1287, 7188,
        1291, 6676, 1293, 5652, 1294, 3604, 1299, 6420, 1301, 5396,
        1302, 3348, 1305, 4884, 1306, 2836, 1308, 1812, 1315, 6292,
        1317, 5268, 1318, 3220, 1321, 4756, 1322, 2708, 1324, 1684,
        1329, 4500, 1330, 2452, 1332, 1428, 1347, 6228, 1349, 5204,
        1350, 3156, 1353, 4692, 1354, 2644, 1356, 1620, 1361, 4436,
        1362, 2388, 1377, 4308, 1378, 2260, 1411, 6196, 1413, 5172,
        1414, 3124, 1417, 4660, 1418, 2612, 1420, 1588, 1425, 4404,
        1426, 2356, 1441, 4276, 1442, 2228, 1473, 4212, 1474, 2164,
        1543, 7180, 1547, 6668, 1549, 5644, 1550, 3596, 1555, 6412,
        1557, 5388, 1558, 3340, 1561, 4876, 1562, 2828, 1564, 1804,
        1571, 6284, 1573, 5260, 1574, 3212, 1577, 4748, 1578, 2700,
        1580, 1676, 1585, 4492, 1586, 2444, 1603, 6220, 1605, 5196,
        1606, 3148, 1609, 4684, 1610, 2636, 1617, 4428, 1618, 2380,
        1633, 4300, 1634, 2252, 1667, 6188, 1669, 5164, 1670, 3116,
        1673, 4652, 1674, 2604, 1681, 4396, 1682, 2348, 1697, 4268,
        1698, 2220, 1729, 4204, 1730, 2156, 1795, 6172, 1797, 5148,
        1798, 3100, 1801, 4636, 1802, 2588, 1809, 4380, 1810, 2332,
        1825, 4252, 1826, 2204, 1857, 4188, 1858, 2140, 1921, 4156,
        1922, 2108, 2063, 7682, 2071, 7426, 2075, 6914, 2077, 5890,
        2078, 3842, 2087, 7298, 2091, 6786, 2093, 5762, 2094, 3714,
        2099, 6530, 2101, 5506, 2102, 3458, 2105, 4994, 2106, 2946,
        2119, 7234, 2123, 6722, 2125, 5698, 2126, 3650, 2131, 6466,
        2133, 5442, 2134, 3394, 2137, 4930, 2138, 2882, 2147, 6338,
        2149, 5314, 2150, 3266, 2153, 4802, 2154, 2754, 2161, 4546,
        2162, 2498, 2183, 7202, 2187, 6690, 2189, 5666, 2190, 3618,
        2195, 6434, 2197, 5410, 2198, 3362, 2201, 4898, 2202, 2850,
        2211, 6306, 2213, 5282, 2214, 3234, 2217, 4770, 2218, 2722,
        2225, 4514, 2226, 2466, 2243, 6242, 2245, 5218, 2246, 3170,
        2249, 4706, 2250, 2658, 2257, 4450, 2258, 2402, 2273, 4322,
        2311, 7186, 2315, 6674, 2317, 5650, 2318, 3602, 2323, 6418,
        2325, 5394, 2326, 3346, 2329, 4882, 2330, 2834, 2339, 6290,
        2341, 5266, 2342, 3218, 2345, 4754, 2346, 2706, 2353, 4498,
        2354, 2450, 2371, 6226, 2373, 5202, 2374, 3154, 2377, 4690,
        2378, 2642, 2385, 4434, 2401, 4306, 2435, 6194, 2437, 5170,
        2438, 3122, 2441, 4658, 2442, 2610, 2449, 4402, 2465, 4274,
        2497, 4210, 2567, 7178, 2571, 6666, 2573, 5642, 2574, 3594,
        2579, 6410, 2581, 5386, 2582, 3338, 2585, 4874, 2586, 2826,
        2595, 6282, 2597, 5258, 2598, 3210, 2601, 4746, 2602, 2698,
        2609, 4490, 2627, 6218, 2629, 5194, 2630, 3146, 2633, 4682,
        2641, 4426, 2657, 4298, 2691, 6186, 2693, 5162, 2694, 3114,
        2697, 4650, 2705, 4394, 2721, 4266, 2753, 4202, 2819, 6170,
        2821, 5146, 2822, 3098, 2825, 4634, 2833, 4378, 2849, 4250,
        2881, 4186, 2945, 4154, 3079, 7174, 3083, 6662, 3085, 5638,
        3086, 3590, 3091, 6406, 3093, 5382, 3094, 3334, 3097, 4870,
        3107, 6278, 3109, 5254, 3110, 3206, 3113, 4742, 3121, 4486,
        3139, 6214, 3141, 5190, 3145, 4678, 3153, 4422, 3169, 4294,
        3203, 6182, 3205, 5158, 3209, 4646, 3217, 4390, 3233, 4262,
        3265, 4198, 3331, 6166, 3333, 5142, 3337, 4630, 3345, 4374,
        3361, 4246, 3393, 4182, 3457, 4150, 3587, 6158, 3589, 5134,
        3593, 4622, 3601, 4366, 3617, 4238, 3649, 4174, 3713, 4142,
        3841, 4126, 4111, 7681, 4119, 7425, 4123, 6913, 4125, 5889,
        4135, 7297, 4139, 6785, 4141, 5761, 4147, 6529, 4149, 5505,
        4153, 4993, 4167, 7233, 4171, 6721, 4173, 5697, 4179, 6465,
        4181, 5441, 4185, 4929, 4195, 6337, 4197, 5313, 4201, 4801,
        4209, 4545, 4231, 7201, 4235, 6689, 4237, 5665, 4243, 6433,
        4245, 5409, 4249, 4897, 4259, 6305, 4261, 5281, 4265, 4769,
        4273, 4513, 4291, 6241, 4293, 5217, 4297, 4705, 4305, 4449,
        4359, 7185, 4363, 6673, 4365, 5649, 4371, 6417, 4373, 5393,
        4377, 4881, 4387, 6289, 4389, 5265, 4393, 4753, 4401, 4497,
        4419, 6225, 4421, 5201, 4425, 4689, 4483, 6193, 4485, 5169,
        4489, 4657, 4615, 7177, 4619, 6665, 4621, 5641, 4627, 6409,
        4629, 5385, 4633, 4873, 4643, 6281, 4645, 5257, 4649, 4745,
        4675, 6217, 4677, 5193, 4739, 6185, 4741, 5161, 4867, 6169,
        4869, 5145, 5127, 7173, 5131, 6661, 5133, 5637, 5139, 6405,
        5141, 5381, 5155, 6277, 5157, 5253, 5187, 6213, 5251, 6181,
        5379, 6165, 5635, 6157, 6151, 7171, 6155, 6659, 6163, 6403,
        6179, 6275, 6211, 5189, 4681, 4433, 4321, 3142, 2634, 2386,
        2274, 1612, 1364, 1252,  856,  744,  496,
        /* Table II 2 of 13. */
           3, 6144,    5, 5120,    6, 3072,    9, 4608,   10, 2560,
          12, 1536,   17, 4352,   18, 2304,   20, 1280,   24,  768,
          33, 4224,   34, 2176,   36, 1152,   40,  640,   48,  384,
          65, 4160,   66, 2112,   68, 1088,   72,  576,   80,  320,
          96,  192,  129, 4128,  130, 2080,  132, 1056,  136,  544,
         144,  288,  257, 4112,  258, 2064,  260, 1040,  264,  528,
         513, 4104,  514, 2056,  516, 1032, 1025, 4100, 1026, 2052,
        2049, 4098, 4097, 2050, 1028,  520,  272,  160
};


/*===========================================*/
/* Local function prototypes                 */
/*===========================================*/
static gboolean     onecode_is_data_valid (const gchar      *data);

static gchar       *onecode_encode        (const gchar      *data);

static lglBarcode  *onecode_vectorize     (const gchar      *code);

static void         int104_mult_uint      (Int104           *x,
                                           guint             y);
static void         int104_add_uint       (Int104           *x,
                                           guint             y);
static void         int104_add_uint64     (Int104           *x,
                                           guint64           y);
static guint        int104_div_uint       (Int104           *x,
                                           guint             y);
#ifdef DEBUG
static void         int104_print          (Int104           *x);
#endif

static unsigned short   USPS_MSB_Math_CRC11GenerateFrameCheckSequence( unsigned char *ByteArrayPtr );


/****************************************************************************/
/* Generate new One Code barcode structure from data.                       */
/****************************************************************************/
lglBarcode *
lgl_barcode_onecode_new (lglBarcodeType  type,
                         gboolean        text_flag,
                         gboolean        checksum_flag,
                         gdouble         w,
                         gdouble         h,
                         const gchar    *data)
{
        gchar              *code;
        lglBarcode         *bc;

        if ( type != LGL_BARCODE_TYPE_ONECODE )
        {
                g_message ("Invalid barcode type for ONECODE backend.");
                return NULL;
        }


        /* Validate data */
        if ( !onecode_is_data_valid (data) )
        {
                return NULL;
        }

        /* Now get code string */
        code = onecode_encode (data);
        if (code == NULL) {
                return NULL;
        }

        /* Now vectorize encoded data. */
        bc = onecode_vectorize (code);

        g_free (code);

        return bc;
}


/*--------------------------------------------------------------------------*/
/* Validate if string is of proper length & contains only valid characters. */
/*--------------------------------------------------------------------------*/
static gboolean
onecode_is_data_valid (const gchar *data)
{
        gchar *p;
        gint   str_length;

        if (!data)
        {
                return FALSE;
        }

        str_length = strlen (data);
        if ( (str_length != 20) &&
             (str_length != 25) &&
             (str_length != 29) &&
             (str_length != 31) )
        {
                return FALSE;
        }

        for ( p = (gchar *)data; *p != 0; p++ )
        {
                if (!g_ascii_isdigit (*p))
                {
                        return FALSE;
                }
        }

        if (data[1] > '4')
        {
                return FALSE; /* Invalid Barcode Identifier. */
        }

        return TRUE;
}


/*--------------------------------------------------------------------------*/
/* PRIVATE.  Generate string of symbols, representing barcode.              */
/*--------------------------------------------------------------------------*/
static gchar *
onecode_encode (const gchar *data)
{
        Int104   value = {{0}};
        gint     i;
        guint    crc11;
        guint    codeword[10];
        guint    character[10];
        gint     d, a;
        GString *code;

        /*-----------------------------------------------------------*/
        /* Step 1 -- Conversion of Data Fields into Binary Data      */
        /*-----------------------------------------------------------*/

        /* Step 1.a -- Routing Code */
        for ( i = 20; data[i] != 0; i++ )
        {
                int104_mult_uint (&value, 10);
                int104_add_uint  (&value, data[i] - '0');
        }
        switch ( i-20 )
        {
        case 0:
                break;
        case 5:
                int104_add_uint  (&value, 1);
                break;
        case 9:
                int104_add_uint  (&value, 1);
                int104_add_uint  (&value, 100000);
                break;
        case 11:
                int104_add_uint   (&value, 1);
                int104_add_uint   (&value, 100000);
                int104_add_uint64 (&value, 1000000000);
                break;
        default:
                return NULL; /* Should not happen if length tests passed. */
                break;
        }

        /* Step 1.b -- Tracking Code */
        int104_mult_uint (&value, 10);
        int104_add_uint  (&value, data[0] - '0');
        int104_mult_uint (&value, 5);
        int104_add_uint  (&value, data[1] - '0');

        for ( i = 2; i < 20; i++ )
        {
                int104_mult_uint (&value, 10);
                int104_add_uint  (&value, data[i] - '0');
        }


        /*-----------------------------------------------------------*/
        /* Step 2 -- Generation of 11-Bit CRC on Binary Data         */
        /*-----------------------------------------------------------*/

        crc11 = USPS_MSB_Math_CRC11GenerateFrameCheckSequence( value.byte );


        /*-----------------------------------------------------------*/
        /* Step 3 -- Conversion of Binary Data to Codewords          */
        /*-----------------------------------------------------------*/

        codeword[9] = int104_div_uint (&value, 636);
        for ( i = 8; i >= 1; i-- )
        {
                codeword[i] = int104_div_uint (&value, 1365);
        }
        codeword[0] = int104_div_uint (&value, 659);


        /*-----------------------------------------------------------*/
        /* Step 4 -- Inserting Additional Information into Codewords */
        /*-----------------------------------------------------------*/

        codeword[9] *= 2;
        codeword[0] += (crc11 & 0x400) ? 659 : 0;


        /*-----------------------------------------------------------*/
        /* Step 5 -- Conversion from Codewords to Characters         */
        /*-----------------------------------------------------------*/

        for ( i = 0; i < 10; i++ )
        {
                character[i] = character_table[ codeword[i] ];

                if ( crc11 & (1<<i) )
                {
                        character[i] = ~character[i] & 0x1FFF;
                }
        }


        /*-----------------------------------------------------------*/
        /* Step 6 -- Conversion from Characters to IMail Barcode     */
        /*-----------------------------------------------------------*/

        code = g_string_new ("");
        for ( i = 0; i < 65; i++ )
        {
                d = (character[ bar_map[i].descender.i ] & bar_map[i].descender.mask) != 0;
                a = (character[ bar_map[i].ascender.i ]  & bar_map[i].ascender.mask)  != 0;

                code = g_string_append (code, tdaf_table[ (a<<1) + d ]);
        }


        return g_string_free (code, FALSE);
}


/*--------------------------------------------------------------------------*/
/* Vectorize encoded data.                                                  */
/*--------------------------------------------------------------------------*/
static lglBarcode *
onecode_vectorize (const gchar  *code)
{
        lglBarcode         *bc;
        gchar              *p;
        gdouble             x, y, length, width;

        bc = lgl_barcode_new ();

        /* Now traverse the code string and create a list of lines */
        x = ONECODE_HORIZ_MARGIN;
        for (p = (gchar *)code; *p != 0; p++)
        {
                y = ONECODE_VERT_MARGIN;
                switch ( *p )
                {
                case 'T':
                        y      += ONECODE_TRACKER_OFFSET;
                        length  = ONECODE_TRACKER_HEIGHT;
                        break;
                case 'D':
                        y      += ONECODE_DESCENDER_OFFSET;
                        length  = ONECODE_DESCENDER_HEIGHT;
                        break;
                case 'A':
                        y      += ONECODE_ASCENDER_OFFSET;
                        length  = ONECODE_ASCENDER_HEIGHT;
                        break;
                case 'F':
                        y      += ONECODE_FULL_OFFSET;
                        length  = ONECODE_FULL_HEIGHT;
                        break;
                default:
                        break;
                }
                width = ONECODE_BAR_WIDTH;

                lgl_barcode_add_box (bc, x, y, width, length);

                x += ONECODE_BAR_PITCH;
        }

        bc->width = x + ONECODE_HORIZ_MARGIN;
        bc->height = ONECODE_FULL_HEIGHT + 2 * ONECODE_VERT_MARGIN;

        return bc;
}


/*--------------------------------------------------------------------------*/
/* Multiply 104 bit integer by unsigned int.                                */
/*--------------------------------------------------------------------------*/
static void
int104_mult_uint (Int104  *x,
                  guint    y)
{
        gint    i;
        guint64 temp, carry;

        carry = 0;
        for ( i = 12; i >= 0; i-- )
        {
                temp = x->byte[i] * y  +  carry;

                x->byte[i] = temp & 0xFF;
                carry      = temp >> 8;
        }
}


/*--------------------------------------------------------------------------*/
/* Add unsigned int to 104 bit integer.                                     */
/*--------------------------------------------------------------------------*/
static void
int104_add_uint (Int104  *x,
                 guint     y)
{
        gint    i;
        guint   temp, carry;

        carry = 0;
        for ( i = 12; i >= 0; i-- )
        {
                temp = x->byte[i] + (y & 0xFF) + carry;

                x->byte[i]  = temp & 0xFF;
                carry       = temp >> 8;
                y           = y >> 8;
        }
}


/*--------------------------------------------------------------------------*/
/* Add unsigned 64 bit integer to 104 bit integer.                          */
/*--------------------------------------------------------------------------*/
static void
int104_add_uint64 (Int104  *x,
                   guint64   y)
{
        gint    i;
        guint64 temp, carry;

        carry = 0;
        for ( i = 12; i >= 0; i-- )
        {
                temp = x->byte[i] + (y & 0xFF) + carry;

                x->byte[i]  = temp & 0xFF;
                carry       = temp >> 8;
                y           = y >> 8;
        }
}


/*--------------------------------------------------------------------------*/
/* Divide 104 bit integer by unsigned int.                                  */
/*--------------------------------------------------------------------------*/
static guint
int104_div_uint (Int104 *x,
                 guint   y)
{
        guint carry, tmp, i;

        carry = 0;
        for ( i = 0; i < 13; i++ )
        {
                tmp        = x->byte[i] + (carry<<8);
                x->byte[i] = tmp / y;
                carry      = tmp % y;
        }

        return carry;
}


/*--------------------------------------------------------------------------*/
/* Print hex representation of 104 bit integer.  (For debugging)            */
/*--------------------------------------------------------------------------*/
#ifdef DEBUG
static void
int104_print (Int104  *x)
{
        gint i;

        for ( i = 0; i < 13; i++ )
        {
                g_print ("%02x ", x->byte[i] & 0xFF);
        }
        g_print ("\n");
}
#endif


/***************************************************************************
 ** USPS_MSB_Math_CRC11GenerateFrameCheckSequence
 **
 ** Inputs:
 **   ByteAttayPtr is the address of a 13 byte array holding 102 bytes which
 **   are right justified - ie: the leftmost 2 bits of the first byte do not
 **   hold data and must be set to zero.
 **
 ** Outputs:
 **   return unsigned short - 11 bit Frame Check Sequence (right justified)
 **
 ** From Appendix C of USPS publication USPS-B-3200E, 07/08/05.
 ***************************************************************************/
unsigned short
USPS_MSB_Math_CRC11GenerateFrameCheckSequence( unsigned char *ByteArrayPtr )
{
        unsigned short  GeneratorPolynomial = 0x0F35;
        unsigned short  FrameCheckSequence  = 0x07FF;
        unsigned short  Data;
        int             ByteIndex, Bit;

        /* Do most significant byte skipping the 2 most significant bits */
        Data = *ByteArrayPtr << 5;
        ByteArrayPtr++;
        for ( Bit = 2; Bit < 8; Bit++ )
        {
                if ( (FrameCheckSequence ^ Data) & 0x400 )
                {
                        FrameCheckSequence = (FrameCheckSequence << 1) ^ GeneratorPolynomial;
                }
                else
                {
                        FrameCheckSequence = (FrameCheckSequence << 1);
                }
                FrameCheckSequence &= 0x7FF;
                Data <<= 1;
        }

        /* Do rest of the bytes */
        for ( ByteIndex = 1; ByteIndex < 13; ByteIndex++ )
        {
                Data = *ByteArrayPtr << 3;
                ByteArrayPtr++;
                for ( Bit = 0; Bit < 8; Bit++ )
                {
                        if ( (FrameCheckSequence ^ Data) & 0x0400 )
                        {
                                FrameCheckSequence = (FrameCheckSequence << 1) ^ GeneratorPolynomial;
                        }
                        else
                        {
                                FrameCheckSequence = (FrameCheckSequence << 1);
                        }
                        FrameCheckSequence &= 0x7FF;
                        Data <<= 1;
                }
        }

        return FrameCheckSequence;
}




/*
 * Local Variables:       -- emacs
 * mode: C                -- emacs
 * c-basic-offset: 8      -- emacs
 * tab-width: 8           -- emacs
 * indent-tabs-mode: nil  -- emacs
 * End:                   -- emacs
 */
